package pl.jtb.ctl.tabory.ui.re.ui.tr;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.SectionPart;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;

import pl.jtb.ctl.tabory.dao.data.vo.TripVO;
import pl.jtb.ctl.tabory.dao.data.vo.VagonVO;
import pl.jtb.ctl.tabory.dao.impl.mybatis.servicemanager.ServiceManager;
import pl.jtb.ctl.tabory.ui.osgi.UiBundleActivator;
import pl.jtb.ctl.tabory.ui.re.beans.TripVagonBean;
import pl.jtb.ctl.tabory.ui.re.osgi.Activator;

public class VagonTripReportSection extends SectionPart {

    public final static String ID = "pl.jtb.ctl.tabory.ui.re.ui.tr.VagonTripReportSection";
    private final Logger log = Logger.getLogger(VagonTripReportSection.class);

    private final static String EXPORT_FOLDER = Platform.getInstanceLocation().getURL().getPath();
    private org.eclipse.swt.widgets.List reportListComposite;
    private Browser reportBrowser;
    private Button buttonCreateReport;

    private List<String> listFileNames = new ArrayList<String>();

    public VagonTripReportSection(Composite parent, FormToolkit toolkit, int style) {
        super(parent, toolkit, style);
        initGui(toolkit);
        postInitGui();
    }

    private void initGui(FormToolkit toolkit) {
        getSection().setText(Activator.getMessage("report.title"));
        Composite container = toolkit.createComposite(getSection());
        GridLayoutFactory.fillDefaults().numColumns(2).applyTo(container);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(container);
        getSection().setClient(container);
        container.setLayout(new GridLayout(2, false));

        Form formReportsList = toolkit.createForm(container);
        formReportsList.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true, 1, 1));
        toolkit.paintBordersFor(formReportsList);
        formReportsList.getBody().setLayout(new GridLayout(1, false));

        buttonCreateReport = toolkit.createButton(formReportsList.getBody(), Activator.getMessage("report.vagon.labels.create"), SWT.NONE);
        buttonCreateReport.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1));

        reportListComposite = new org.eclipse.swt.widgets.List(formReportsList.getBody(), SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
        GridData gd_reportListComposite = new GridData(SWT.FILL, SWT.FILL, false, true, 1, 1);
        gd_reportListComposite.widthHint = 200;
        reportListComposite.setLayoutData(gd_reportListComposite);
        toolkit.adapt(reportListComposite, true, true);

        Menu popupMenu = new Menu(reportListComposite);
        MenuItem copyToClipboarItem = new MenuItem(popupMenu, SWT.NONE);
        copyToClipboarItem.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                new CopyFileToClipboar().run();
            }
        });
        copyToClipboarItem.setText(Activator.getMessage("report.listreports.popupmenu.copy"));
        reportListComposite.setMenu(popupMenu);

        Form formReportViewer = toolkit.createForm(container);
        formReportViewer.setTouchEnabled(true);
        formReportViewer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
        toolkit.paintBordersFor(formReportViewer);
        formReportViewer.getBody().setLayout(new GridLayout(1, false));

        reportBrowser = new Browser(formReportViewer.getBody(), SWT.BORDER);
        reportBrowser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
        toolkit.adapt(reportBrowser);
        toolkit.paintBordersFor(reportBrowser);
    }

    private void postInitGui() {
        fillListFiles();
        reportListComposite.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseDoubleClick(MouseEvent e) {
                org.eclipse.swt.widgets.List source = (org.eclipse.swt.widgets.List) e.getSource();
                String[] selection = source.getSelection();
                String selectedFile = selection[0];
                performOpenReport(selectedFile);
            }
        });
        buttonCreateReport.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent event) {
                try {
                    performCreateReport();
                } catch (InvocationTargetException e) {
                    log.error(e.getMessage(), e);
                    MessageDialog.openError(getSection().getShell(), UiBundleActivator.getMessage("common.dialog.error.title"), UiBundleActivator.getMessage("common.dialog.error.title"));
                } catch (InterruptedException e) {
                    log.error(e.getMessage(), e);
                    MessageDialog.openError(getSection().getShell(), UiBundleActivator.getMessage("common.dialog.error.title"), UiBundleActivator.getMessage("common.dialog.error.title"));
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                    MessageDialog.openError(getSection().getShell(), UiBundleActivator.getMessage("common.dialog.error.title"), UiBundleActivator.getMessage("common.dialog.error.title"));
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                    MessageDialog.openError(getSection().getShell(), UiBundleActivator.getMessage("common.dialog.error.title"), UiBundleActivator.getMessage("common.dialog.error.title"));
                }
            }
        });
    }

    private void performCreateReport() throws IOException, Exception {
        List<VagonVO> listAllVagons = ServiceManager.getInstance().getVagonService().getListAllVagons();
        TripReportDialog dialog = new TripReportDialog(getSection().getShell(), listAllVagons);
        int open = dialog.open();
        if (open == Window.OK) {
            Date resultDateFrom = dialog.getResultDateFrom();
            Date resultDateUntil = dialog.getResultDateUntil();
            VagonVO resultVagon = dialog.getResultVagon();
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
            StringBuilder builder = new StringBuilder(Activator.getMessage("report.vagon.newreport.defaultname"));
            builder.append("_");
            builder.append(dateFormat.format(new Date()));
            InputDialog stationNameInputDialog = new InputDialog(getSection().getShell(), Activator.getMessage("report.vagon.create.title"), Activator.getMessage("report.vagon.create.message"), builder.toString(), null);
            if (Window.OK == stationNameInputDialog.open()) {
                final String reportName = stationNameInputDialog.getValue();
                if (reportName.isEmpty()) {
                    return;
                }
                if (reportName.contains(".")) {
                    MessageDialog.openError(getSection().getShell(), Activator.getMessage("report.vagon.create.wrongname.title"), Activator.getMessage("report.vagon.create.wrongname.message"));
                    return;
                }
                PlatformUI.getWorkbench().getProgressService().run(false, true, new ReportCreatorRunnable(reportName, resultVagon));
            }
        } else {
            return;
        }
    }

    private class ReportCreatorRunnable implements IRunnableWithProgress {

        private String reportName;
        private VagonVO vagon;

        public ReportCreatorRunnable(String reportName, VagonVO vagon) {
            this.reportName = reportName;
            this.vagon = vagon;
        }

        @Override
        public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
            try {
                monitor.beginTask(Activator.getMessage("report.common.doing"), 5);
                String exportPath = EXPORT_FOLDER + "/" + reportName + ".pdf";
                monitor.worked(1);
                InputStream reportStream = this.getClass().getResourceAsStream("/resources/ctl_wyjazdy.jasper");
                monitor.worked(2);
                Map<String, Object> parametersMap = new HashMap<String, Object>();
                JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(getBeans(vagon));
                JasperPrint jasperPrint = JasperFillManager.fillReport(reportStream, parametersMap, dataSource);
                monitor.worked(3);
                JasperExportManager.exportReportToPdfFile(jasperPrint, exportPath);
                monitor.worked(4);
                fillListFiles();
                monitor.worked(5);
                String reportFileName = reportName + ".pdf";
                performOpenReport(reportFileName);
                reportListComposite.setSelection(listFileNames.indexOf(reportFileName));
                monitor.done();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                MessageDialog.openError(getSection().getShell(), UiBundleActivator.getMessage("common.dialog.error.title"), UiBundleActivator.getMessage("common.dialog.error.title"));
            }
        }

    }

    private void fillListFiles() {
        reportListComposite.removeAll();
        File workspaceFolder = new File(EXPORT_FOLDER);
        File[] listFiles = workspaceFolder.listFiles();
        listFileNames.clear();
        if (listFiles != null) {
            for (File file : listFiles) {
                if (file.getName().endsWith(".pdf")) {
                    reportListComposite.add(file.getName());
                    listFileNames.add(file.getName());
                }
            }
        }
    }

    private void performOpenReport(String selectedFile) {
        reportBrowser.setUrl(new File(EXPORT_FOLDER + "\\" + selectedFile).toString());
        reportBrowser.setFocus();
    }

    private List<TripVagonBean> getBeans(VagonVO vagon) throws IOException, Exception {
        List<TripVO> tripsForVagon = ServiceManager.getInstance().getTripService().getTripsForVagon(vagon.getId());
        List<TripVagonBean> result = new ArrayList<TripVagonBean>();
        for (TripVO trip : tripsForVagon) {
            String stationFromName = trip.getStationFrom() == null ? "---" : trip.getStationFrom().getStationName();
            String stationToName = trip.getStationTo() == null ? "---" : trip.getStationTo().getStationName();
            TripVagonBean bean = new TripVagonBean(vagon.getInternalId(), stationFromName, stationToName, trip.getDateFrom(), trip.getDateUntil(), trip.getDistanceKm());
            result.add(bean);
        }
        return result;
    }

    private class CopyFileToClipboar extends Thread {
        @Override
        public void run() {
            Display display = Display.getCurrent();
            Clipboard clipboard = new Clipboard(display);
            String[] selection = reportListComposite.getSelection();
            String fileName = selection[0];
            if (fileName == null || fileName.isEmpty()) {
                return;
            }
            fileName = EXPORT_FOLDER + fileName;
            fileName = fileName.substring(1, fileName.length());
            String[] data = { fileName };
            clipboard.setContents(new Object[] { data }, new Transfer[] { FileTransfer.getInstance() });
            clipboard.dispose();
        }
    }
}
